package made.util;

import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;


public class GameStateRecorder implements Config
{
    protected static GameStateRecorder instance = null;
    protected static String filename = "StatRecorder" + getDateTime() + ".txt";
    protected static int previousScore = 0;
    protected GameStateAnalyzer _analyzer;
    protected int[] _sampleTypeCount;
    protected HashSet<String> _uniqueSamples;
    protected boolean _samplesComplete;
    protected final int _sampleTypeCountThreshold;

    protected GameStateRecorder()
    {
        _analyzer = new GameStateAnalyzer();
        _sampleTypeCount = new int[4];
        _uniqueSamples = new HashSet<String>(500);
        _sampleTypeCountThreshold = 99;
    }

    public void init()
    {
        _samplesComplete = false;

        for (int i = 0; i < _sampleTypeCount.length; i++)
        {
            _sampleTypeCount[i] = 0;
        }

        _uniqueSamples.clear();
    }

    public static GameStateRecorder getInstance()
    {
        if (instance == null)
        {
            instance = new GameStateRecorder();
        }

        return instance;
    }

    public void initFilename(String prefix)
    {
        filename = "/GA/" + prefix + getDateTime() + ".txt";
    }

    public String getCurrentFilename()
    {
        return filepath + filename;
    }

    public boolean saveBaselinePacManSample(int edibleTime, int nearestPillDistance, int nearestGhostDistance, ACTION action, int sampleType)
    {
        if (_samplesComplete)
            return _samplesComplete;

        if (_sampleTypeCount[0] > _sampleTypeCountThreshold && _sampleTypeCount[1] > _sampleTypeCountThreshold
                && _sampleTypeCount[2] > _sampleTypeCountThreshold && _sampleTypeCount[3] > _sampleTypeCountThreshold)
        {
            writeLineToFile("COMPLETE SET");
            _samplesComplete = true;
            return _samplesComplete;
        }

        if (_sampleTypeCount[sampleType] > _sampleTypeCountThreshold)
        {
            if (MPM_DEBUG_LEVEL == DEBUG_LEVEL.VERBOSE)
                Logger.logLine("Sample limit for sample type " + sampleType + " reached. Sample was not saved.");
            return _samplesComplete;
        }

        float edibleTimeNorm = _analyzer.getNormalizedEdibleTime(edibleTime);
        float nearestPillDistanceNorm = _analyzer.getNormalizedPathDistance(nearestPillDistance);
        float nearestGhostDistanceNorm = _analyzer.getNormalizedPathDistance(nearestGhostDistance);
        String ANNInput = edibleTimeNorm + " " + nearestPillDistanceNorm + " " + nearestGhostDistanceNorm;
        String ANNOutput = actionToANNOutput(action);
        String sample = ANNInput + " " + ANNOutput;

        if (_uniqueSamples.add(sample))
        {
            if (MPM_DEBUG_LEVEL == DEBUG_LEVEL.VERBOSE)
                Logger.logLine("Baseline Pac Man stats: " + sample);

            writeLineToFile(sample);
            _sampleTypeCount[sampleType]++;
        } else
        {
            if (MPM_DEBUG_LEVEL == DEBUG_LEVEL.VERBOSE)
                Logger.logLine("Identical sample already recorded. Sample was not saved.");
        }

        return _samplesComplete;
    }

    public String actionToANNOutput(ACTION action)
    {
        if (action == ACTION.TO_NEAREST_PILL)
            return "1.0 0.0 0.0";
        else if (action == ACTION.TO_NEAREST_GHOST)
            return "0.0 1.0 0.0";
        else if (action == ACTION.FROM_NEAREST_GHOST)
            return "0.0 0.0 1.0";
        else
            return "0.0 0.0 1.0";
    }

    public void writeLineToFile(String line)
    {
        // System.out.println("Writing line...");
        BufferedWriter bufferedWriter = null;

        try
        {
            bufferedWriter = new BufferedWriter(new FileWriter(filepath + filename, true));
            bufferedWriter.write(line);
            bufferedWriter.newLine();

        } catch (FileNotFoundException ex)
        {
            ex.printStackTrace();
        } catch (IOException ex)
        {
            ex.printStackTrace();
        } finally
        {
            // Close the BufferedWriter
            try
            {
                if (bufferedWriter != null)
                {
                    bufferedWriter.flush();
                    bufferedWriter.close();
                }
            } catch (IOException ex)
            {
                ex.printStackTrace();
            }
        }
    }

    public void printSampleTypeStats()
    {
        Logger.logLine(_sampleTypeCount[0] + " " + _sampleTypeCount[1] + " " + _sampleTypeCount[2] + " " + _sampleTypeCount[3]);
    }

    protected static String getDateTime()
    {
        DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        Date date = new Date();
        return dateFormat.format(date);
    }

    public enum UNIQUE_STATE_TYPE
    {
        ETL
    }
};
